import Vector2 from "../vector";
import Board, { BoardCell } from "./board";

/** 药丸  */
export default abstract class PillState {
  /** 网格坐标  */
  readonly gridPos: Vector2;
  readonly board: Board;

  abstract get matrix(): number[][]; // 2*2

  constructor(gridPos: Vector2, board: Board) {
    this.gridPos = gridPos;
    this.board = board;
  }

  abstract canMove(dx: number, dy: number): boolean;
  abstract canRotate(isCW: boolean): boolean;

  canFall(fallRows: number) {
    return this.canMove(0, fallRows);
  }

  move(dx: number, dy: number) {
    this.setBoardState(false);
    this.gridPos.x += dx;
    this.gridPos.y += dy;
    this.setBoardState(true);
  }

  rotate(isCW: boolean) {}

  fall(fallRows: number) {
    this.move(0, fallRows);
  }

  abstract setBoardState(isErase: boolean): void;
}

export class SmallPillState extends PillState {
  /** 消除判断相同的值 */
  readonly value: number;

  get matrix() {
    return [[this.value, 0], [0, 0]];
  }

  constructor(gridPos: Vector2, value: number, board: Board) {
    super(gridPos, board);
    this.value = value;
  }

  canMove(dx: number, dy: number) {
    return this.board.isSpace(this.gridPos.x + dx, this.gridPos.y + dy);
  }

  canRotate(isCW: boolean) { return false; }

  setBoardState(notErase: boolean) {
    this.board.setCell(this.gridPos.x, this.gridPos.y,
      notErase ? new BoardCell(this.value, this) : BoardCell.Empty);
  }
}

export class BigPillState extends PillState {
  gridPos: Vector2;
  /** 消除判断相同的值 
   * value存储两个部分：坐和右，或上和下部分
   */
  value: [number, number];
  /** 是否垂直状态 */
  private _isVertical = false;
  get isVertical() { return this._isVertical; }

  get matrix() {
    const m = [[this.value[0], 0], [0, 0]];
    if (this._isVertical) {
      m[1][0] = this.value[1];
    } else {
      m[0][1] = this.value[1];
    }
    return m;
  }

  constructor(gridPos: Vector2, value: [number, number], board: Board) {
    super(gridPos, board);
    this.value = value;
  }

  canMove(dx: number, dy: number) {
    let ret = true;
    this.setBoardState(false); // 避免与自己碰撞
    for (let r = 0; r < 2; r++) {
      for (let c = 0; c < 2; c++) {
        if (this.matrix[r][c] &&
          !this.board.isSpace(this.gridPos.x + c + dx, this.gridPos.y + r + dy)) {
          ret = false;
          break;
        }
      }
    }
    this.setBoardState(true);
    return ret;
  }

  canRotate(isCW: boolean) {
    if (this._isVertical) {
      return this.board.isSpace(this.gridPos.x + 1, this.gridPos.y);
    } else {
      return this.board.isSpace(this.gridPos.x, this.gridPos.y + 1);
    }
  }

  rotate(isCW: boolean) {
    this.setBoardState(false);
    if (this._isVertical) {
      // 如果当前已经是垂直，现在转成水平，则现在交换两个部分的相对位置
      const [ l, r ] = this.value;
      this.value[0] = r;
      this.value[1] = l;
    }
    this._isVertical = !this._isVertical;
    this.setBoardState(true);
  }

  part(parted: number) {
    const i = this.value.findIndex((v) => v == parted);
    this.value[i] = 0;
  }

  isSmall() {
    return this.value.reduce((s, v) => v == 0 ? s : s + 1, 0) < 2;
  }

  tryToSmall() {
    if (!this.isSmall()) {
      return false;
    }
    const val = this.value.find((v) => v);
    if (!val) {
      return false;
    }
    const cell = this.board.find((cell) => cell.obj == this);
    return new SmallPillState(
      new Vector2(cell.pos.x, cell.pos.y), val, this.board);
  }

  setBoardState(notErase: boolean) {
    const { board, gridPos } = this;
    for (let r = 0; r < 2; r++) {
      for (let c = 0; c < 2; c++) {
        const val = this.matrix[r][c];
        if (val && board.isBoundPos(gridPos.x + c, gridPos.y + r)) {
          board.setCell(gridPos.x + c, gridPos.y + r,
            notErase ? new BoardCell(val, this) : BoardCell.Empty);
        }
      }
    }
  }
}